﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ExcelConverter;
using LitJson;

namespace JsonToCSharp
{
    public static class ItemConverter
    {
        private static Encoding s_encoding = new UTF8Encoding(false);
        
        private const string INT_FORMAT = @"using System.Collections.Generic;
using LitJson;
using System;

namespace Config
<<
    [Serializable]
    public class {0} : {6}.AConfigItem, {6}.IJsonFile
    <<
        public string FileName => ""{3}"";
        public string FilePath => ""{4}"";
        public string FilePathNonSuffix => ""{5}"";

{1}

        public override void Init(JsonData data)
        <<
{2}
        >>
    >>
>>";
        private const string STRING_FORMAT = @"using System.Collections.Generic;
using LitJson;
using System;

namespace Config
<<
    [Serializable]
    public class {0} : {6}.SConfigItem, {6}.IJsonFile
    <<
        public string FileName => ""{3}"";
        public string FilePath => ""{4}"";
        public string FilePathNonSuffix => ""{5}"";

{1}

        public override void Init(JsonData data)
        <<
{2}
        >>
    >>
>>";
        private const string PROTOTYPE_FORMAT = @"namespace Config
<<
    public class {0} : {1}, {5}.IJsonFile
    <<
        public string FileName => ""{2}"";
        public string FilePath => ""{3}"";
        public string FilePathNonSuffix => ""{4}"";
    >>
>>";
        
        public static bool Convert(string srcPath, string destPath, string namespacePrefix)
        {
            var lastDivIndex = srcPath.LastIndexOf('\\');
            var fileName = srcPath.Substring(lastDivIndex + 1, srcPath.Length - lastDivIndex - 1);
            var fileNameNonExt = fileName.Substring(0, fileName.Length - 5);
            
            var isIntId = true;
            var varList = new List<string>();
            var varCtorList = new List<string>();
            string prototypeName = null;
            var data = JsonMapper.ToObject(File.ReadAllText(srcPath));
            if (data.Count != 0)
            {
                var first = data[0];
                if (first.ContainsKey("__prototype"))
                {
                    prototypeName = first["__prototype"].ToString();
                }
                else
                {
                    var keys = first.Keys;
                    foreach (var key in keys)
                    {
                        var spiltIndex = key.IndexOf('_');
                        var type = key.Substring(0, spiltIndex);
                        var name = key.Substring(spiltIndex + 1, key.Length - spiltIndex - 1);
                        //跳过id列
                        if (key == "i_id")
                        {
                            isIntId = true;
                            varCtorList.Add($"            {name} = int.Parse(data[\"{key}\"].ToString());");
                            continue;
                        }
                        if (key == "s_id")
                        {
                            isIntId = false;
                            varCtorList.Add($"            {name} = data[\"{key}\"].ToString();");
                            continue;
                        }
                        //赋值
                        switch (type)
                        {
                            //整数
                            case "i":
							//时间戳
                            case "t":
                            {
                                varList.Add($"        public long {name};");
                                varCtorList.Add($"            {name} = long.Parse(data[\"{key}\"].ToString());");
                                break;
                            }
                            case "il":
                            {
                                varList.Add($"        public int[] {name};");
                                var varCtor = string.Format(@"            var {0}__DATA = data[""{1}""];
            var {0}__COUNT = {0}__DATA.Count;
            {0} = new int[{0}__COUNT];
            for (var i = 0; i < {0}__COUNT; i++)
            <<
                {0}[i] = int.Parse({0}__DATA[i].ToString());
            >>", name, key);
                                varCtorList.Add(varCtor);
                                break;
                            }
                            case "ill":
                            {
                                varList.Add($"        public int[][] {name};");
                                var varCtor = string.Format(@"            var {0}__DATA = data[""{1}""];
            var {0}__COUNT = {0}__DATA.Count;
            {0} = new int[{0}__COUNT][];
            for (var i = 0; i < {0}__COUNT; i++)
            <<
                var NESTING_DATA = {0}__DATA[i];
                var NESTING_DATA_COUNT = NESTING_DATA.Count;
                var NESTING_ARR = new int[NESTING_DATA_COUNT];
                for (var j = 0; j < NESTING_DATA_COUNT; j++)
                <<
                    NESTING_ARR[j] = int.Parse(NESTING_DATA[j].ToString());
                >>
                {0}[i] = NESTING_ARR;
            >>", name, key);
                                varCtorList.Add(varCtor);
                                break;
                            }
                            //无符号长整数
                            case "u":
                            {
                                varList.Add($"        public ulong {name};");
                                varCtorList.Add($"            {name} = ulong.Parse(data[\"{key}\"].ToString());");
                                break;
                            }
                            case "ul":
                            {
                                varList.Add($"        public ulong[] {name};");
                                var varCtor = string.Format(@"            var {0}__DATA = data[""{1}""];
            var {0}__COUNT = {0}__DATA.Count;
            {0} = new ulong[{0}__COUNT];
            for (var i = 0; i < {0}__COUNT; i++)
            <<
                {0}[i] = ulong.Parse({0}__DATA[i].ToString());
            >>", name, key);
                                varCtorList.Add(varCtor);
                                break;
                            }
                            case "ull":
                            {
                                varList.Add($"        public ulong[][] {name};");
                                var varCtor = string.Format(@"            var {0}__DATA = data[""{1}""];
            var {0}__COUNT = {0}__DATA.Count;
            {0} = new ulong[{0}__COUNT][];
            for (var i = 0; i < {0}__COUNT; i++)
            <<
                var NESTING_DATA = {0}__DATA[i];
                var NESTING_DATA_COUNT = NESTING_DATA.Count;
                var NESTING_ARR = new ulong[NESTING_DATA_COUNT];
                for (var j = 0; j < NESTING_DATA_COUNT; j++)
                <<
                    NESTING_ARR[j] = ulong.Parse(NESTING_DATA[j].ToString());
                >>
                {0}[i] = NESTING_ARR;
            >>", name, key);
                                varCtorList.Add(varCtor);
                                break;
                            }
                            //浮点数
                            case "f":
                            {
                                varList.Add($"        public float {name};");
                                varCtorList.Add($"            {name} = float.Parse(data[\"{key}\"].ToString());");
                                break;
                            }
                            case "fl":
                            {
                                varList.Add($"        public float[] {name};");
                                var varCtor = string.Format(@"            var {0}__DATA = data[""{1}""];
            var {0}__COUNT = {0}__DATA.Count;
            {0} = new float[{0}__COUNT];
            for (var i = 0; i < {0}__COUNT; i++)
            <<
                {0}[i] = float.Parse({0}__DATA[i].ToString());
            >>", name, key);
                                varCtorList.Add(varCtor);
                                break;
                            }
                            case "fll":
                            {
                                varList.Add($"        public float[][] {name};");
                                var varCtor = string.Format(@"            var {0}__DATA = data[""{1}""];
            var {0}__COUNT = {0}__DATA.Count;
            {0} = new float[{0}__COUNT][];
            for (var i = 0; i < {0}__COUNT; i++)
            <<
                var NESTING_DATA = {0}__DATA[i];
                var NESTING_DATA_COUNT = NESTING_DATA.Count;
                var NESTING_ARR = new float[NESTING_DATA_COUNT];
                for (var j = 0; j < NESTING_DATA_COUNT; j++)
                <<
                    NESTING_ARR[j] = float.Parse(NESTING_DATA[j].ToString());
                >>
                {0}[i] = NESTING_ARR;
            >>", name, key);
                                varCtorList.Add(varCtor);
                                break;
                            }
                            //布尔值
                            case "b":
                            {
                                varList.Add($"        public bool {name};");
                                varCtorList.Add($"            {name} = data[\"{key}\"].ToString()[0] == '1';");
                                break;
                            }
                            case "bl":
                            {
                                varList.Add($"        public bool[] {name};");
                                var varCtor = string.Format(@"            var {0}__DATA = data[""{1}""];
            var {0}__COUNT = {0}__DATA.Count;
            {0} = new bool[{0}__COUNT];
            for (var i = 0; i < {0}__COUNT; i++)
            <<
                {0}[i] = {0}__DATA[i].ToString()[0] == '1';
            >>", name, key);
                                varCtorList.Add(varCtor);
                                break;
                            }
                            case "bll":
                            {
                                varList.Add($"        public bool[][] {name};");
                                var varCtor = string.Format(@"            var {0}__DATA = data[""{1}""];
            var {0}__COUNT = {0}__DATA.Count;
            {0} = new bool[{0}__COUNT][];
            for (var i = 0; i < {0}__COUNT; i++)
            <<
                var NESTING_DATA = {0}__DATA[i];
                var NESTING_DATA_COUNT = NESTING_DATA.Count;
                var NESTING_ARR = new bool[NESTING_DATA_COUNT];
                for (var j = 0; j < NESTING_DATA_COUNT; j++)
                <<
                    NESTING_ARR[j] = NESTING_DATA[j].ToString()[0] == '1';
                >>
                {0}[i] = NESTING_ARR;
            >>", name, key);
                                varCtorList.Add(varCtor);
                                break;
                            }
                            //字符串
                            case "s":
                            {
                                varList.Add($"        public string {name};");
                                varCtorList.Add($"            {name} = data[\"{key}\"].ToString();");
                                break;
                            }
                            case "sl":
                            {
                                varList.Add($"        public string[] {name};");
                                var varCtor = string.Format(@"            var {0}__DATA = data[""{1}""];
            var {0}__COUNT = {0}__DATA.Count;
            {0} = new string[{0}__COUNT];
            for (var i = 0; i < {0}__COUNT; i++)
            <<
                {0}[i] = {0}__DATA[i].ToString();
            >>", name, key);
                                varCtorList.Add(varCtor);
                                break;
                            }
                            case "sll":
                            {
                                varList.Add($"        public string[][] {name};");
                                var varCtor = string.Format(@"            var {0}__DATA = data[""{1}""];
            var {0}__COUNT = {0}__DATA.Count;
            {0} = new string[{0}__COUNT][];
            for (var i = 0; i < {0}__COUNT; i++)
            <<
                var NESTING_DATA = {0}__DATA[i];
                var NESTING_DATA_COUNT = NESTING_DATA.Count;
                var NESTING_ARR = new string[NESTING_DATA_COUNT];
                for (var j = 0; j < NESTING_DATA_COUNT; j++)
                <<
                    NESTING_ARR[j] = NESTING_DATA[j].ToString();
                >>
                {0}[i] = NESTING_ARR;
            >>", name, key);
                                varCtorList.Add(varCtor);
                                break;
                            }
                            default:
                            {
                                MainWindow.ShowTip($"未知变量类型: {type}\n({fileName})");
                                return false;
                            }
                        }
                    }
                }
            }

            var classNameStr = fileNameNonExt.Substring(fileNameNonExt.LastIndexOf('.') + 1);
            if (!classNameStr.EndsWith("Template"))
            {
                classNameStr += "Item";
            }
            string content;
            var path = $"Configs/{namespacePrefix}";
            if (!string.IsNullOrEmpty(namespacePrefix)) path += "/";
            var ns = $"{namespacePrefix}Config";
            if (string.IsNullOrEmpty(prototypeName))
            {
                var varListStr = string.Join("\n", varList);
                var varCtorListStr = string.Join("\n", varCtorList);
                content = string.Format(isIntId ? INT_FORMAT : STRING_FORMAT, 
                    classNameStr,   //类名
                    varListStr,     //变量申明
                    varCtorListStr, //变量构造
                    fileNameNonExt,      //文件名
                    $"{path}{fileName}", //文件路径
                    $"{path}{fileNameNonExt}", //文件路径（不带后缀）
                    ns); //命名空间
            }
            else
            {
                content = string.Format(PROTOTYPE_FORMAT, 
                    classNameStr,   //类名
                    prototypeName,  //继承类名
                    fileNameNonExt,      //文件名
                    $"{path}{fileName}", //文件路径
                    $"{path}{fileNameNonExt}", //文件路径（不带后缀）
                    ns); //命名空间
            }
            content = content.Replace("<<", "{");
            content = content.Replace(">>", "}");
            File.WriteAllText(Path.Combine(destPath, $"{classNameStr}.cs"), content, s_encoding);
            return true;
        }
    }
}